package com.baishui.beans.factory.support;

import com.baishui.beans.BeanDefinition;
import com.baishui.beans.BeansException;
import com.baishui.beans.factory.FactoryBean;
import com.baishui.beans.factory.config.ConfigurableBeanFactory;
import com.baishui.beans.factory.config.RuntimeBeanReference;
import com.baishui.beans.factory.config.TypedStringValue;
import com.baishui.beans.factory.exception.BeanCreationException;

/**
 * 解析property中的属性，转换成真正的实例对象
 */
public class BeanDefinitionValueResolver {

	/**
	 *  需要获取已经创建好的bean的信息
	 *  最小原则
	 */
	private final AbstractBeanFactory beanFactory;

	public BeanDefinitionValueResolver(AbstractBeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	public Object resolveValueIfNecessary(Object value) {
		
		if (value instanceof RuntimeBeanReference) {
			RuntimeBeanReference ref = (RuntimeBeanReference) value;			
			String refName = ref.getBeanName();

			/**
			 * 从工厂中获取bean的实例对象
			 */
			Object bean = this.beanFactory.getBean(refName);				
			return bean;
			
		}else if (value instanceof TypedStringValue) {
			/**
			 *  直接字符串返回
			 */
			return ((TypedStringValue) value).getValue();
		} else if (value instanceof BeanDefinition) {
			// Resolve plain BeanDefinition, without contained name: use dummy name.
			BeanDefinition bd = (BeanDefinition) value;

			String innerBeanName = "(inner bean)" + bd.getBeanClassName() + "#" +
					Integer.toHexString(System.identityHashCode(bd));

			return resolveInnerBean(innerBeanName, bd);
		}
		else{
			return value;
		}		
	}

	private Object resolveInnerBean(String innerBeanName, BeanDefinition innerBd) {

		try {
			Object innerBean = this.beanFactory.createBean(innerBd);
			/**
			 * TODO 重要
			 */
			if (innerBean instanceof FactoryBean) {
				try {
					return ((FactoryBean<?>)innerBean).getObject();
				} catch (Exception e) {
					throw new BeanCreationException(innerBeanName, "FactoryBean threw exception on object creation", e);
				}
			} else {
				return innerBean;
			}
			} catch (BeansException ex) {
				throw new BeanCreationException(
					innerBeanName,
					"Cannot create inner bean '" + innerBeanName + "' " +
							(innerBd != null && innerBd.getBeanClassName() != null ? "of type [" + innerBd.getBeanClassName() + "] " : "")
					, ex);
		}
	}
}
